package com.degani.pdf;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class MainFrame extends JFrame {
	private static Logger logger = Logger.getLogger(MainFrame.class);
	private static final long serialVersionUID = 1L;
	private static MainFrame instance;
	private static Properties folderProps = new Properties();
	private static FieldMap fieldMap = new FieldMap();
	private static Executor templateExecutor;
	
	private JProgressBar progressBar;
	private JLabel labelStatusMessage;
	private JButton buttonProcess;	
	private JTable tablePreview;
	private DefaultTableModel tableModel;
	
	
	
	static {
		instance = new MainFrame("Planancial Excel Report Generator");
	}
	
	public static MainFrame getInstance(){
		return instance;
	}

	public String getExcelTemplate() {
		return excelTemplate;
	}

	public void setExcelTemplate(String excelTemplate) {
		this.excelTemplate = excelTemplate;
	}

	public String getPdfFolder() {
		return pdfFolder;
	}

	public void setPdfFolder(String pdfFolder) {
		this.pdfFolder = pdfFolder;
	}

	public String getOutputFolder() {
		return outputFolder;
	}

	public void setOutputFolder(String outputFolder) {
		this.outputFolder = outputFolder;
	}

	private String excelTemplate;
	private String pdfFolder;
	private String outputFolder;

	private MainFrame(String title) {
		super(title);
		initProps();
		initUI();
	}
	
	private File[] getInputForms(){
		File f = new File(getPdfFolder());
		if(f.isDirectory()){
			return f.listFiles(new FilenameFilter() {
				@Override
				public boolean accept(File arg0, String arg1) {
					// TODO Auto-generated method stub
					return arg1.endsWith(".pdf");
				}
			});
		}
		return new File[0];
	}

	private void refreshTable(){
		tableModel.setRowCount(0);
		
		for(File inputPdf : getInputForms()){
			tableModel.addRow(new Object[]{
					inputPdf.getName(), 
					"NOTSTARTED",
					PDFExtractor.getFormField(
						inputPdf.getAbsolutePath(), "Name")
			});
		}
	}
	
	protected void initUI(){
		progressBar = new JProgressBar();
		progressBar.setStringPainted(true);
		
		labelStatusMessage = new JLabel(String.format(
				"<html>Found <b>%d</b> pdf file(s) in \"%s\"</html>", 
				getInputForms().length, getPdfFolder()));
		buttonProcess = new JButton("Process");	
		tableModel = new DefaultTableModel(
				new Object[]{"File", "Status", "Name"}, 0){
			private static final long serialVersionUID = 1L;
			
			@Override
			public boolean isCellEditable(int row, int col) {
				return false;
			}
		};
		tablePreview = new JTable(tableModel);
		tablePreview.getColumn("Status").setCellRenderer(new StatusRenderer());
		refreshTable();
		
		JPanel panel = new JPanel(new BorderLayout(5,5));
		JPanel bottomPanel = new JPanel(new BorderLayout(5,0));
		panel.add(labelStatusMessage, BorderLayout.NORTH);

		panel.add(new JScrollPane(tablePreview),BorderLayout.CENTER);
		
		bottomPanel.add(progressBar, BorderLayout.CENTER);
		bottomPanel.add(buttonProcess, BorderLayout.EAST);
		panel.add(bottomPanel,BorderLayout.SOUTH);
		panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		
		setContentPane(panel);
		
		final Progress p = new UIProgress(progressBar, labelStatusMessage);
		buttonProcess.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				templateExecutor.execute(new Runnable(){
					@Override
					public void run() {
						try{
							List<String>pdfNames = new ArrayList<String>();
							File[] pdfFiles = getInputForms();
							for(File pdfFile : pdfFiles){
								pdfNames.add(pdfFile.getAbsolutePath());
							}							
							PDFExtractor.process(pdfNames, excelTemplate, 
								fieldMap, outputFolder, p);
							p.setStatusMessage("Completed.");
						} catch(Exception e){
							logger.error("Unexpected error occured while processing", e);
							SwingUtilities.invokeLater(new Runnable() {
								
								@Override
								public void run() {
									JOptionPane.showMessageDialog(MainFrame.getInstance(), 
											"Unexpected error while processing.\nPlease see application.log for more details.");
								}
							});
						}
					}
				});
			}
		});
	}
	
	protected void initProps() {
		// load up configuration
		String folderFile = "./config/folder.properties";
		
		try {
			folderProps.load(new FileInputStream(folderFile));
			setExcelTemplate(folderProps.get("ExcelTemplate").toString());
			setPdfFolder(folderProps.get("PDFFolder").toString());
			setOutputFolder(folderProps.get("OutputFolder").toString());
		} catch (FileNotFoundException e) {
			logger.error("Could not find properties file: " + folderFile, e);
		} catch (IOException e) {
			logger.error("Error while initializing properties", e);
		}
		String mappingsFile = "./config/mapping.properties";
		try {
			fieldMap.load(new FileInputStream(mappingsFile));
		} catch (FileNotFoundException e) {
			logger.error("Could not find properties file: " + mappingsFile, e);
		} catch (IOException e) {
			logger.error("Error while initializing properties", e);
		}
	}
	
	public static void main(String[] args) throws FileNotFoundException, IOException {
		PropertyConfigurator.configure("./config/log4j.properties");
		logger.debug("Starting Application");
		templateExecutor = new ScheduledThreadPoolExecutor(3);
		
		/*
	    try {
            // Set cross-platform Java L&F (also called "Metal")
	    	UIManager.setLookAndFeel(UIManager.get());
	    } 
	    catch (UnsupportedLookAndFeelException e) {
	       logger.error("Could not set look and feel",e);
	    }
	    catch (ClassNotFoundException e) {
	    	logger.error("Could not set look and feel",e);
	    }
	    catch (InstantiationException e) {
	    	logger.error("Could not set look and feel",e);
	    }
	    catch (IllegalAccessException e) {
	    	logger.error("Could not set look and feel",e);
	    }		
		*/
		
		final MainFrame frame = MainFrame.getInstance();
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				//frame.setResizable(false);
				frame.setSize(400, 300);
				frame.setVisible(true);
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			}
		});
	}
	
	private static class StatusRenderer extends DefaultTableCellRenderer {
	    private static Color DARK_GREEN = Color.GREEN.darker().darker();
		public StatusRenderer() { super(); }

	    public void setValue(Object value) {
	        super.setValue(value);
	        if("ERROR".equals(value)){
	        	setForeground(Color.RED);
	        }
	        else if("DONE".equals(value)){
	        	setForeground(DARK_GREEN);
	        }
	        else {
	        	setForeground(Color.BLACK);
	        }
	    }
	}
	
	private class UIProgress implements Progress {
		private int progress;
		private String statusMessage;
		
		private JProgressBar uiProgressBar;
		private JLabel statusLabel;

		public UIProgress(JProgressBar uiProgressBar, 
				JLabel statusLabel) {
			this.uiProgressBar = uiProgressBar;
			this.statusLabel = statusLabel;
		}
		
		public int getProgress() {
			return progress;
		}
		
		public void setProgress(int progress) {
			this.progress = progress;
			final int uiProgress = this.progress; 
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					uiProgressBar.setValue(uiProgress);
				}
			});
		}
		
		@Override
		public String getStatusMessage() {
			// TODO Auto-generated method stub
			return statusMessage;
		}
		
		@Override
		public void setStatusMessage(String message) {
			this.statusMessage = message;
			final String uiStatusMessage = this.statusMessage;
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					statusLabel.setText(uiStatusMessage);
				}
			});
		}
	}
}
